﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using MOJsdk;
using System.Text.RegularExpressions;
using System.Collections.ObjectModel;
using Forms = System.Windows.Forms;
using DetectLanguage02;
using System.Threading;
using System.Windows.Threading;
using IO = System.IO;

namespace MOJ
{
    /// <summary>
    /// Interaction logic for Control_SearchMovies_Prepare.xaml
    /// </summary>
    public partial class Control_SearchMovies_Prepare : UserControl
    {
        public Control_SearchMovies_Prepare()
        {
            InitializeComponent();
            INI();
        }
        private ProcessReport _reporter;

        #region Inicialization
        private void INI()
        {
            INIEvents();
            INIStyle();
        }

        private void INIEvents()
        {
            _btn_setfolder.Click += SetFolder;
            _btn_start.Click += StartProcess;
        }
        private void INIStyle()
        {
            if (!GlobalVars.TheHost.SystemVars.VarExist("MoJBrowseFilesDir"))
                GlobalVars.TheHost.SystemVars.SetVar("MoJBrowseFilesDir", @"c:\");

            _txtBox_Folder.Text = GlobalVars.TheHost.SystemVars.GetVar("MoJBrowseFilesDir");
            _txtBox_movies.Text = GlobalVars.TheHost.SystemVars.GetVar("VideoType");
            _txtBox_subtitles.Text = GlobalVars.TheHost.SystemVars.GetVar("SubtitleType");

            _progBar.Maximum = 100;
            _progBar.Value = 0;

            _btn_start.Content = MOJLocalization.Localize("Start");
            _lbl_folder.Content = MOJLocalization.Localize("Folder") + ": ";
            _lbl_movies.Content = MOJLocalization.Localize("Movies") + ": ";
            _lbl_subtitles.Content = MOJLocalization.Localize("Subtitles") + ": ";

            _Grid.ApplyStyle("0101107");
            _lbl_folder.ApplyStyle("0101108");
            _lbl_movies.ApplyStyle("0101109");
            _lbl_subtitles.ApplyStyle("0101110");
            _txtBox_Folder.ApplyStyle("0101111");
            _txtBox_movies.ApplyStyle("0101112");
            _txtBox_subtitles.ApplyStyle("0101113");
            _btn_setfolder.ApplyStyle("0101114");
            _btn_start.ApplyStyle("0101115");
            _rect_diviser.ApplyStyle("0101116");
            _listBox.ApplyStyle("0101117");
            _progBar.ApplyStyle("0101118");
            _progBar_infinite.ApplyStyle("0101119");
        }
        #endregion

        private void SetFolder(object sender, RoutedEventArgs e)
        {
            Forms.FolderBrowserDialog diag = new Forms.FolderBrowserDialog();
            if (diag.ShowDialog() == Forms.DialogResult.OK)
            {
                _txtBox_Folder.Text = diag.SelectedPath;
            }
        }
        private void StartProcess(object sender, RoutedEventArgs e)
        {
            if (_txtBox_Folder.Text.IsNullorEmpty() || _txtBox_movies.Text.IsNullorEmpty())
                return;

            _txtBox_Folder.IsEnabled = false;
            _txtBox_movies.IsEnabled = false;
            _txtBox_subtitles.IsEnabled = false;
            _btn_setfolder.IsEnabled = false;
            _btn_start.IsEnabled = false;

            _progBar_infinite.IsIndeterminate = true;
            GlobalVars.TheHost.SystemVars.SetVar("MoJBrowseFilesDir", _txtBox_Folder.Text);
            GlobalVars.TheHost.SystemVars.SetVar("VideoType", _txtBox_movies.Text);
            GlobalVars.TheHost.SystemVars.SetVar("SubtitleType", _txtBox_subtitles.Text);

            Thread3Params th = new Thread3Params(ProcessFilesAsync);
            th.BeginInvoke(_txtBox_Folder.Text, _txtBox_movies.Text, _txtBox_subtitles.Text, null, null);
        }
        private void ProcessFilesAsync(string folder, string filterMovies, string filterSubs)
        {
            try
            {
                _reporter = new ProcessReport();

                AddListBoxEntry("Loading Movie Files...");
                List<FilePreProcessDetails> list = new List<FilePreProcessDetails>();
                if (!filterMovies.IsNullorEmpty())
                    list = new List<FilePreProcessDetails>(GetFiles(folder, filterMovies));
                AddListBoxEntry("Completed");

                int NumFiles = list.Count;
                int Files2Process = NumFiles;
                int FilesProcessed = 0;

                InternetInfo info = new InternetInfo(TOOLS.TMDB_APIKey);

                #region AddMovieFiles
                foreach (var v in list)
                {
                    AddListBoxEntry("---------------------------");
                    AddListBoxEntry("Remain Movie Files: " + Files2Process.ToString());
                    AddListBoxEntry("---------------------------");

                    Files2Process--;
                    FilesProcessed++;

                    AddListBoxEntry(string.Format("Processing File {0}/{1}: ", FilesProcessed, NumFiles));
                    if (v.IsBlackListed)
                    {
                        AllAlertListBox(string.Format("File {0} is Black listed", v.FilePath));
                        AddListBoxEntry(string.Format("****Completed File {0}******", FilesProcessed));
                        SetProgBar(FilesProcessed, NumFiles);
                        _reporter.AddInsucess(v, "Blacklist");
                        continue;
                    }

                    MojWebMovie _movie = null;

                    AddListBoxEntry(string.Format("Searching Movie \"{0}\" ...", v.FileProcessedName));
                    _movie = FindMovie(v, info.SearchMovie(v.FileProcessedName), v.FileProcessedName);
                    if (_movie == null || _movie.IsBlacklisted)
                    {
                        AddListBoxEntry(string.Format("Cant find Movie \"{0}\" ...", v.FileProcessedName));
                        AddListBoxEntry(string.Format("Searching Movie \"{0}\" ...", v.DirectoryProcessedName));
                        _movie = FindMovie(v, info.SearchMovie(v.DirectoryProcessedName), v.DirectoryProcessedName);
                    }


                    if (_movie == null)
                    {
                        AllAlertListBox("Movie not found for file:");
                        AllAlertListBox(v.FilePath);
                        _reporter.AddInsucess(v, "Movie not identified");
                    }
                    else if (_movie.IsBlacklisted)
                    {
                        AllAlertListBox(string.Format("Movie {0} ({1}) is Blacklisted", _movie.Title, _movie.Imdb_Id));
                        AllAlertListBox(v.FilePath);
                        _reporter.AddInsucess(v, string.Format("Movie {0} ({1}) is Blacklisted", _movie.Title, _movie.Imdb_Id));
                    }
                    else if (_movie != null)
                    {
                        AddListBoxEntry("Movie  for file:");
                        AddListBoxEntry(v.FilePath);
                        AddListBoxEntry("Indentified as: " + _movie.Title + "(" + _movie.Year + ")");
                        AddMovie(_movie, v);
                    }

                    AddListBoxEntry(string.Format("****Completed File {0}******", FilesProcessed));
                    SetProgBar(FilesProcessed, NumFiles);
                }
                #endregion

                AddListBoxEntry("Loading Subtitles...");
                List<FilePreProcessDetails> listSubs = new List<FilePreProcessDetails>();
                if (!filterSubs.IsNullorEmpty())
                    listSubs = new List<FilePreProcessDetails>(GetFiles(folder, filterSubs));
                AddListBoxEntry("Completed");

                int NumSubs = listSubs.Count;
                int Subs2Process = NumSubs;
                int SubsProcessed = 0;

                #region AddSubFiles
                foreach (var v in listSubs)
                {
                    AddListBoxEntry("---------------------------");
                    AddListBoxEntry("Remain Sub Files: " + Subs2Process.ToString());
                    AddListBoxEntry("---------------------------");

                    Subs2Process--;
                    SubsProcessed++;

                    AddListBoxEntry(string.Format("Processing File {0}/{1}: ", SubsProcessed, NumSubs));

                    MojWebMovie _movie = null;

                    AddListBoxEntry(string.Format("Searching Movie \"{0}\" ...", v.FileProcessedName));
                    _movie = FindMovie(v, info.SearchMovie(v.FileProcessedName), v.FileProcessedName);
                    if (_movie == null)
                    {
                        AddListBoxEntry(string.Format("Cant find Movie \"{0}\" ...", v.FileProcessedName));
                        AddListBoxEntry(string.Format("Searching Movie \"{0}\" ...", v.DirectoryProcessedName));
                        _movie = FindMovie(v, info.SearchMovie(v.DirectoryProcessedName), v.DirectoryProcessedName);
                    }

                    if (_movie != null)
                    {
                        AddListBoxEntry("Movie  for file:");
                        AddListBoxEntry(v.FilePath);
                        AddListBoxEntry("Indentified as: " + _movie.Title + "(" + _movie.Year + ")");
                        AddSub(_movie, v);
                    }
                    else
                    {
                        AllAlertListBox("Movie not found for file:");
                        AllAlertListBox(v.FilePath);
                        _reporter.AddInsucess(v, "Movie not identified");
                    }

                    AddListBoxEntry(string.Format("****Completed File {0}******", Subs2Process));
                    SetProgBar(SubsProcessed, NumSubs);
                }
                #endregion

                CompleteProcess();
            }
            catch (Exception ex)
            {
                GlobalVars.TheHost.ReportError(new ErrorReporter()
                {
                    ErrorCode = "Control_SearchMovies_Prepare.ProcessFilesAsync",
                    ErrorMessage = "Error processing files",
                    ErrorDetails = ex.ToString(),
                });
            }
        }

        private List<FilePreProcessDetails> GetFiles(string Folder, string filter)
        {
            List<string> DB_Files = new List<string>(GlobalVars.TheHost.GetFiles().Select(z=>z.FileFullPath.ToLower()));
            List<FilePreProcessDetails> list = new List<FilePreProcessDetails>();

            foreach (var v in TOOLS.GetFiles(Folder, filter))
            {
                list.Add(new FilePreProcessDetails(v));
            }

            return list;
        }
        private MojWebMovie FindMovie(FilePreProcessDetails File, List<MojWebMovie> movies, string query)
        {
            if (movies.Count == 0)
                return null;

            string year = File.FileYear != null ? File.FileYear : File.DirectoryYear;
            if (year != null)
            {
                int xCount = movies.Where(z => z.Year == year).Count();
                if (xCount == 1)
                    return movies.Where(z => z.Year == year).First();
                else if (xCount > 1)
                    movies = new List<MojWebMovie>(movies.Where(z => z.Year == year));
            }

            List<int> list = new List<int>();
            for (int i = 0; i < movies.Count; i++)
            {
                int x = TOOLS.DamerauLevenshteinDistance(query.ToLower(), movies[i].Title.ToLower());
                list.Add(x);
            }

            int min = list.Min();
            if (list.Count(z => z == min) >= 1)
            {
                for (int i = 0; i < movies.Count; i++)
                    if (list[i] == min)
                        return movies[i];
            }

            return null;
        }
        private void AddMovie(MojWebMovie TheMovie, FilePreProcessDetails File)
        {
            #region Add New Movie
            if (!GlobalVars.TheHost.MovieExistInDataBase(TheMovie.MovieId))
            {
                MOJBasicMovieClass MOVIE = TheMovie.GetMoJMovieClass;

                TheMovie.Cover.DownloadOriginalFile();
                MOJBasicFileClass IMAGE = TheMovie.Cover.GetMoJImageClass();
                IMAGE.MovieCode = MOVIE.MovieCode;
                IMAGE.FileID = GlobalVars.TheHost.AddNewFileToDataBase(IMAGE);
                if (IMAGE.FileID == -1)
                {
                    return;
                }

                MOVIE.CoverID = IMAGE.FileID;
                if (!GlobalVars.TheHost.AddNewMovieToDataBase(MOVIE))
                {
                    GlobalVars.TheHost.RemoveFileFromDataBase(IMAGE.FileID);
                    return;
                }
                _reporter.NewMovies.Add(TheMovie.MovieId);
            }
            #endregion

            MOJBasicFileClass.AddNewMojBasicFile(File.FilePath, MOJFileTypes.MovieFile, TheMovie.MovieId);
            _reporter.AddSucess(File, TheMovie.MovieId);
        }
        private void AddSub(MojWebMovie TheMovie, FilePreProcessDetails File)
        {
            if (GlobalVars.TheHost.MovieExistInDataBase(TheMovie.MovieId))
            {

                int i = 0;

                if (GlobalVars.TheHost.SystemVars.GetVar("MoJ_UseLangDetector").ToBool())
                    i = GetLanguage(File.FilePath);

                
                MOJMovie m = new MOJMovie(TheMovie.MovieId);
                if (m.ContainsSubtitle(ISO639_1.LoadLanguage(i)))
                {
                    AddListBoxEntry(string.Format("Movie {0} already has a {1} Subtitle", 
                        TheMovie.Title, ISO639_1.LoadLanguage(i).Country));
                    return;
                }

                MOJBasicFileClass.AddNewMojBasicFile(File.FilePath, MOJFileTypes.SubtitleFile, TheMovie.MovieId, i);
                _reporter.AddSucess(File, TheMovie.MovieId);
            }
            else
            {
                AddListBoxEntry(string.Format("Movie {0} not found in database", TheMovie.Title));
                GlobalVars.TheHost.AddFileToFilePool(File.FilePath);
                _reporter.AddInsucess(File, string.Format("Movie {0} not found in database", TheMovie.Title));
            }
        }
        private int GetLanguage(string FilePath)
        {
            if (IO.Path.GetExtension(FilePath).ToLower() != ".srt")
                return 1;

            string API = GlobalVars.TheHost.SystemVars.GetVar("MoJ_Lang_API_KEY");
            string text = IO.File.ReadAllText(FilePath);

            AddListBoxEntry("Searching Subtitle Language");
            DetectLanguage detector = new DetectLanguage(API);
            LanguagePool pool = detector.SmartDetect(text);

            if (pool == null)
            {
                AddListBoxEntry("Language not detected");
                return 1;
            }

            DetectLanguageResult result = pool.GetBestResult();
            if (result != null)
            {
                AddListBoxEntry(string.Format("Subtitles detected as {0} - {1} - {2}",
                    result.Lang, result.Confidence, result.IsReliable));
                return ISO639_1.GetLanguageIndex(result.Lang);
            }

            AddListBoxEntry("Language not detected");
            return 1;
        }

        private void AddListBoxEntry(string entry)
        {
            DispatcherOperation op = this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate
            {
                _listBox.Items.Add(_listBox.Items.Count.ToString() + " - " +  entry);
                _listBox.ScrollIntoView(_listBox.Items[_listBox.Items.Count - 1]);
            });
            while (op.Status != DispatcherOperationStatus.Completed) { }
        }
        private void AllAlertListBox(string entry)
        {
            DispatcherOperation op = this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate
            {
                TextBlock txt = new TextBlock();
                txt.Foreground = Brushes.Red;
                txt.Text = _listBox.Items.Count.ToString() + " - " + entry;
                _listBox.Items.Add(txt);
                _listBox.ScrollIntoView(_listBox.Items[_listBox.Items.Count - 1]);
            });
            while (op.Status != DispatcherOperationStatus.Completed) { }
        }
        private void RefreshListBox(int value)
        {
            this.Dispatcher.BeginInvoke(DispatcherPriority.Send, (ThreadStart)delegate
            {
                _listBox.Items.Clear();
                _listBox.Items.Add("Filtering files " + value.ToString());
            });
        }
        private void SetProgBar(int value, int max)
        {
            this.Dispatcher.BeginInvoke(DispatcherPriority.Send, (ThreadStart)delegate
            {
                _progBar.Maximum = max;
                _progBar.Value = value;
            });
        }
        private void CompleteProcess()
        {
            this.Dispatcher.BeginInvoke(DispatcherPriority.Send, (ThreadStart)delegate
            {
                _progBar_infinite.IsIndeterminate = false;
                GlobalVars.TheHost.ShowMessage(string.Format("{0} Files added to database", 
                    _reporter.FilesAdded.Count), "Complete");
                GlobalVars.TheHost.ReloadElementsInfo();
                _reporter.WriteReport(_listBox);
            });
        }

        private delegate void Thread3Params(string folder, string filterMovies, string filterSubs);
    }

    public class FilePreProcessDetails
    {
        private List<string> _blacklist;

        public FilePreProcessDetails(string path)
        {
            if (!IO.File.Exists(path))
                return;

            FilePath = path;
            _blacklist = new List<string>(GlobalVars.TheHost.SystemVars.GetVar("MoJFileIgnore").ToList(";"));
            FileProcessedName = GetName(FileName);
            FileYear = GetYear(FileName);

            DirectoryProcessedName = GetName(DirectoryName);
            DirectoryYear = GetYear(DirectoryName);
        }

        private string GetName(string target)
        {

            target = target.Replace(".", " ");
            target = target.Replace("(", "");
            target = target.Replace(")", "");
            target = target.Replace("[", "");
            target = target.Replace("]", "");
            target = target.Replace("-", "");

            foreach (var v in _blacklist)
                target = target.ToLower().Replace(v.ToLower(), "");

            if (target.Length < 5)
                return target;

            string sub = target.Substring(4);
            var _match = Regex.Match(sub, @"\d{4}");
            if (_match.Success)
                target = target.Substring(0,_match.Index + 4);

            return target;
        }
        private string GetYear(string target)
        {
            if (target.Length < 5)
                return null;

            string sub = target.Substring(4);
            var _match = Regex.Match(sub, @"\d{4}");
            if (_match.Success)
                target = _match.Value;
            else
                target = null;

            return target;
        }

        public string FilePath
        { get; set; }
        public string FileName
        { get { return IO.Path.GetFileNameWithoutExtension(FilePath); } }
        public string FileProcessedName
        { get; set; }
        public string FileYear
        { get; set; }
        public string DirectoryName
        {
            get
            {
                string p = IO.Path.GetDirectoryName(FilePath);
                int x = p.LastIndexOf("\\") + 1;
                return p.Substring(x);
            }
        }
        public string DirectoryProcessedName
        { get; set; }
        public string DirectoryYear
        { get; set; }

        public string Report
        {get;set;}

        public bool IsBlackListed
        {
            get
            {
                foreach (var v in GlobalVars.TheHost.SystemVars.GetVar("MoJFileBlackList").ToList(";"))
                {
                    if (FileProcessedName.ToLower().IndexOf(v.ToLower()) != -1)
                        return true;
                }

                return false;
            }
        }
    }
    public class ProcessReport
    {
        public ProcessReport()
        {
            NewMovies = new List<string>();
            FilesAdded = new List<FilePreProcessDetails>();
            FilesNotAdded = new List<FilePreProcessDetails>();
        }

        public List<string> NewMovies
        { get; set; }
        public List<FilePreProcessDetails> FilesAdded
        { get; set; }
        public List<FilePreProcessDetails> FilesNotAdded
        { get; set; }

        public void AddSucess(FilePreProcessDetails file, string MovieID)
        {
            file.Report = MovieID;
            FilesAdded.Add(file);
        }
        public void AddInsucess(FilePreProcessDetails file, string Report)
        {
            file.Report = Report;
            FilesNotAdded.Add(file);
        }

        public void WriteReport(ListBox _list)
        {
            _list.Items.Clear();

            _list.Items.Add("**********************");
            _list.Items.Add("******* Report *******");
            _list.Items.Add("**********************");
            _list.Items.Add(string.Format("New Movies Added {0}: ", NewMovies.Count));

            int count = 0;
            foreach (var v in NewMovies)
            {
                count++;
                MOJMovie m = new MOJMovie(v);

                _list.Items.Add(string.Format("{0}- {1} ({2})", count, m.MovieTitle, m.MovieYear));
            }
            _list.Items.Add("**********************");
            _list.Items.Add(string.Format("New Files Added {0}: ", FilesAdded.Count));

            count = 0;
            foreach (var v in FilesAdded)
            {
                count++;
                _list.Items.Add(string.Format("** File {0} **", count));
                _list.Items.Add(v.FilePath);

                MOJMovie m = new MOJMovie(v.Report);
                _list.Items.Add(string.Format("Identified as {0} ({1})", m.MovieTitle, m.MovieYear));

                _list.Items.Add("*************");
            }


            _list.Items.Add("**********************");
            _list.Items.Add(string.Format("Files not Added {0}: ", FilesNotAdded.Count));

            count = 0; foreach (var v in FilesNotAdded)
            {
                count++;
                _list.Items.Add(string.Format("** File {0} **", count));
                _list.Items.Add(v.FilePath);
                _list.Items.Add(string.Format("Reason: {0})", v.Report));

                _list.Items.Add("*************");
            }
        }
    }
}
